package com.hylanda.nifi.processor.ams.processors.RFMAnalyzeModel;


import com.googlecode.jsonrpc4j.JsonRpcHttpClient;

import java.io.IOException;
import java.net.*;
import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;

public class DockerHolder {
    public final static String PSC_SERVICE_API = "http://psc-internal.hylanda.com/api";
    public final static String DOCKER_REGISTRY = "registry-vpc.cn-hangzhou.aliyuncs.com";
    //换vpc机器的时候用这个：registry-vpc.cn-hangzhou.aliyuncs.com
    public final static String DOCKER_IMAGE_NAME = DOCKER_REGISTRY+"/hailiang/rfm";
    protected DockerProcThread m_dockerThread = null;
    protected Thread m_thread = null;
    private JsonRpcHttpClient _request_client = null;
    private int m_nPort  = -1;
    public String getSvrShowUrlForWlan(String user_id, String project_id ){
        try {
            JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(PSC_SERVICE_API));
            client.setConnectionTimeoutMillis(10000);
            client.setReadTimeoutMillis(30000);

            String strRet = client.invoke("project.get_proxy_secret",
                    new Object[] {"rfm",user_id,project_id,m_nPort}, String.class);
            if (strRet != null && !strRet.isEmpty()){

                String url = strRet;
                System.out.println(url);
                return url;
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return "";
    }

    public String getLastDockerImageTagName() {
        String tagType = "online";
        try {
            JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(PSC_SERVICE_API));
            client.setConnectionTimeoutMillis(10000);
            client.setReadTimeoutMillis(30000);
            String strRet = client.invoke("project.get_docker_image_tag",
                    new Object[] {DOCKER_IMAGE_NAME,tagType}, String.class);
            if (strRet != null && !strRet.isEmpty()){
                System.out.println("get last image tag is"+strRet);
                return strRet;
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return tagType;
    }

    public class DockerProcThread implements Runnable {
        private String m_strDockerImageTag = "";
        private String m_strIdentify = "";
        protected Integer m_nPort = 5000;
        private ReentrantLock m_initLock = new ReentrantLock();
        protected int m_nExitVal = 0;
        private boolean m_bInited = false;
        private boolean m_bInitSuc = false;

        protected Process m_procSvr = null;
        protected String m_strSvrApiUrl = null;

        public void setup(String identify, String strDockerImageTag, int nPort) {
            m_strDockerImageTag = strDockerImageTag;
            m_nPort = nPort;
            m_strIdentify = identify;
            String strHost = System.getenv().get("DOCKER_HOST_ADDR");
            if (strHost == null || strHost.isEmpty()) {
                strHost = "127.0.0.1";
            }
            m_strSvrApiUrl = String.format("http://%1$s:%2$d/api", strHost, nPort);
            System.out.println("api url : " + m_strSvrApiUrl);
        }

        public boolean getInited() {
            return m_bInited;
        }

        public ReentrantLock getInitLock() {
            return m_initLock;
        }

        public int getExitVal() {
            return m_nExitVal;
        }

        public String getSvrApiUrl() {
            return m_strSvrApiUrl;
        }

        private void runOnceCmd(Runtime rt,String cmd){
            if (rt == null){
                rt = Runtime.getRuntime();
            }
            System.out.println(cmd);
            try {
                Process proc = rt.exec(cmd);
                StreamReader error = new StreamReader(proc.getErrorStream(), "Error");
                StreamReader output = new StreamReader(proc.getInputStream(), "Output");
                proc.getOutputStream().close();
                error.start();
                output.start();
                error.join();
                output.join();
                proc.waitFor();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            try {
                if (m_initLock.tryLock()) {
                    //先杀死进程，防止之前异常中断，进程还存在
                    Runtime rt = Runtime.getRuntime();
                    runOnceCmd(rt,"docker rm -f rfm_" + m_strIdentify);
                    runOnceCmd(rt,"service docker start");
                    runOnceCmd(rt, "docker login -u docker@wingfield -p hailiang123 "+DOCKER_REGISTRY);
                    //再启动, 服务进程
                    String strRunCmd = String.format("docker run -t --rm -p %3$d:5000 --name=rfm_%1$s %4$s:%2$s", m_strIdentify, m_strDockerImageTag, m_nPort.intValue(),DOCKER_IMAGE_NAME);
                    System.out.println(strRunCmd);
                    m_procSvr = rt.exec(strRunCmd);

                    StreamReader error = new StreamReader(m_procSvr.getErrorStream(), "Error");
                    StreamReader output = new StreamReader(m_procSvr.getInputStream(), "Output");

                    m_procSvr.getOutputStream().close();

                    error.start();
                    output.start();
                    boolean bInitSuccess = false;
                    //等待服务真正能使用
                    Thread.sleep(3000);
                    for (int i = 0; i < 100; i++) {
                        try {
                            JsonRpcHttpClient client = new JsonRpcHttpClient(new URL(m_strSvrApiUrl));
                            String strRet = client.invoke("RFM.reset", new Object[]{}, String.class);
                            if (strRet.equals("0")) {
                                m_bInitSuc = true;
                                break;
                            } else {
                                System.out.print(strRet);
                            }
                        } catch (Throwable throwable) {
                            throwable.printStackTrace();
                        }
                        Thread.sleep(1000);
                    }

                    m_bInited = true;
                    m_initLock.unlock();
                    error.join();
                    output.join();
                }

                m_nExitVal = m_procSvr.waitFor();

                if (m_nExitVal != 0) {
                    //error
                    System.out.println("run docker cmd error! exitValue: " + m_nExitVal);
                }
            } catch (Throwable t) {
                t.printStackTrace();
                m_bInited = true;
                m_initLock.unlock();
            }
        }

        public void stop() {
            m_bInited = false;
            m_procSvr.destroy();
            runOnceCmd(Runtime.getRuntime(),"docker rm -f rfm_" + m_strIdentify);
        }
    }

    public void init(String proc_id) {

        m_dockerThread = new DockerHolder.DockerProcThread();

        m_nPort = getFreePort(30001, 40000);

        m_dockerThread.setup(proc_id,
                getLastDockerImageTagName(),
                m_nPort);
        m_thread = new Thread(m_dockerThread);
        m_thread.start();

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            _request_client = new JsonRpcHttpClient(new URL(m_dockerThread.getSvrApiUrl()));
            _request_client.setConnectionTimeoutMillis(10000);
            _request_client.setReadTimeoutMillis(30000);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }

    public boolean IsInitSuc() {

        waitInited();
        return m_dockerThread.getExitVal() == 0 && m_dockerThread.m_bInitSuc == true;
    }


    //停止进程
    public void uninit() {
        m_dockerThread.stop();
        if (!m_thread.isInterrupted()) {
            m_thread.interrupt();
            m_thread.destroy();
        }
    }

    /***
     * 请求服务进行计算
     * @param
     * @return
     */
    public String calc(String func, Object params) throws Throwable {
        waitInited();
        return _request_client.invoke(func, params, String.class);
    }

    public static int getFreePort(int nMinPort, int nMaxPort) {//获取空闲端口
        Random r = new Random();
        for (int i = nMinPort; i <= nMaxPort; i++) {
            int port = nMinPort + r.nextInt(nMaxPort - nMinPort);
            String host = System.getenv().get("DOCKER_HOST_ADDR");
            if (host == null || host.isEmpty()) {
                host = "127.0.0.1";
            }
            Socket socket = new Socket();
            try {
                socket.connect(new InetSocketAddress(host, port));
            } catch (IOException e) {
                //e.printStackTrace();
                return port;
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    //e.printStackTrace();
                }
            }
        }
        return -1;
    }

    public void waitInited() {
        while (!m_dockerThread.getInited()) {
            if (m_dockerThread.getInitLock().tryLock()) {
                if (!m_dockerThread.getInited()) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    m_dockerThread.getInitLock().unlock();
                    break;
                }
                m_dockerThread.getInitLock().unlock();
            }
        }
    }
}

